package znet

import (
	"fmt"
	"net"
	"zinx/ziface"

	"zinx/utils"
)

type Server struct {
	//服务器的名称
	Name string
	//tcp4 or other
	IPVersion string
	//服务绑定的IP地址
	IP string
	//服务绑定的端口
	Port int
	//当前server添加一个router，server注册的链接对应的处理业务
	// Router ziface.IRouter
	//当前Server的消息管理模块，用来绑定MsgId和对应的处理方法
	msgHandler ziface.IMsgHandle
}

//定义当前客户端所绑定的handle api（目前的这个handle是写死的，以后优化应由用户自定义handle方法
/*
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	//回显业务
	fmt.Println("[Conn Handle] CallBackToClient ... ")
	if _, err := conn.Write(data[:cnt]); err !=nil {
		fmt.Println("write back buf err ", err)
		return errors.New("CallBackToClient error")
	}
	return nil
}
*/

func (s *Server) Start() {
	//启动服务器
	//全局参数调试信息
	fmt.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.IP, s.Port)
	fmt.Printf("[Zinx] Version: %s, MaxConn: %d,  MaxPacketSize: %d\n",
		utils.GlobalObject.Version,
		utils.GlobalObject.MaxConn,
		utils.GlobalObject.MaxPacketSize)
	fmt.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.IP, s.Port)

	
	go func() { //防止一直阻塞，所以这里把整个程序用go func()承载？？？？？？？？？？
		//现在需要将消息队列和多任务worker机制集成到我们Zinx的中了。我们在Server的Start()方法中，在服务端Accept之前，启动Worker工作池。
		s.msgHandler.StartWorkerPool()
		//1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr err: ", err)
			return
		}

		//2 监听服务器地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err", err)
			return
		}

		//已经监听成功
		fmt.Println("start Zinx server  ", s.Name, " succ, now listenning...")
		//TODO server.go 应该有一个自动生成ID的方法
		var cid uint32
		cid = 0 //随便写一个connID

		// 阻塞等待客户端连接，处理客户端基本链接业务（读写）
		for {
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err ", err)
				continue
			}
			fmt.Println("Get conn remote addr = ", conn.RemoteAddr().String())
			// dealConn := NewConntion(conn, cid, CallBackToClient)  //把conn和 方法CallBackToClient连接在一起
			dealConn := NewConntion(conn, cid, s.msgHandler) //把conn和 方法CallBackToClient连接在一起

			cid++
			//启动当前的连接业务处理
			go dealConn.Start()
			/*
				//客户端连接上的话
				go func() {
					for {
						buf := make([]byte, 512)   //以512字节读数据
						cnt, err := conn.Read(buf) //发数据就read然后回显给客户端
						if err != nil {
							fmt.Println("recv buf err", err)
							continue
						}
						//回显功能
						if _, err := conn.Write(buf[0:cnt]); err != nil { //切片长度，从0到cnt使已经读到的长度
							fmt.Println("write back buf err", err)
							continue
						}

					}
				}() //这里的括号别忘了
			*/
		}
	}()

}

func (s *Server) Stop() {
	//将其他需要清理的连接信息或者其他信息 也要一并停止或者清理

	fmt.Println("[STOP] Zinx server , name ", s.Name)

	//将服务器资源、状态、连接信息进行停止或者回收
}

func (s *Server) Serve() {
	//启动
	s.Start()
	//在这阻塞而不是在Start()阻塞是为了，做一些启动服务器之后的额外业务。Start只用来监听和处理业务。Serve用来阻塞，做其他事情
	select {}
}

//路由功能：给当前服务注册一个路由业务方法，供客户端链接处理使用
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.msgHandler.AddRouter(msgId, router)

	fmt.Println("Add Router succ! ")
}

//初始化server
/*
func NewServer(name string) ziface.IServer {
	s := &Server{
		Name:      name,
		IPVersion: "tcp4",
		IP:        "0.0.0.0",
		Port:      8999,
		Router:    nil,
	}
	return s
}
*/

//这时候就要加载配置文件了
/*
  创建一个服务器句柄
*/
func NewServer() ziface.IServer {
	//先初始化全局配置文件
	utils.GlobalObject.Reload()

	s := &Server{
		Name:      utils.GlobalObject.Name, //从全局参数获取
		IPVersion: "tcp4",
		IP:        utils.GlobalObject.Host,    //从全局参数获取
		Port:      utils.GlobalObject.TcpPort, //从全局参数获取
		msgHandler: NewMsgHandle(), //msgHandler 初始化
	}
	return s
}
